package com.nuoniu.sibanyun.service.erp.barcode.impl;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.nuoniu.sibanyun.common.exception.NuoNiuException;
import com.nuoniu.sibanyun.common.lang.StringUtils;
import com.nuoniu.sibanyun.entity.bo.VoucherDetailBo;
import com.nuoniu.sibanyun.entity.bo.VoucherMainBo;
import com.nuoniu.sibanyun.entity.bo.VoucherSearchBo;
import com.nuoniu.sibanyun.entity.dto.BarcodeMainInfoSearchDto;
import com.nuoniu.sibanyun.entity.dto.ErpNsInOutMainSearchDto;
import com.nuoniu.sibanyun.entity.erp.ErpNumberSet;
import com.nuoniu.sibanyun.entity.erp.barcode.ErpNsInOutDetail;
import com.nuoniu.sibanyun.entity.erp.barcode.ErpNsInOutMain;
import com.nuoniu.sibanyun.entity.so.VAreaCalculationDetail;
import com.nuoniu.sibanyun.entity.so.VAreaCalculationMain;
import com.nuoniu.sibanyun.entity.so.VSaleOrderDetail;
import com.nuoniu.sibanyun.entity.so.VSaleOrderMain;
import com.nuoniu.sibanyun.mapper.erp.ErpNumberSetMapper;
import com.nuoniu.sibanyun.mapper.erp.barcode.ErpNsInOutMainMapper;
import com.nuoniu.sibanyun.service.crm.ICrmGoodsService;
import com.nuoniu.sibanyun.service.erp.IErpAccountService;
import com.nuoniu.sibanyun.service.erp.IErpNumberSetService;
import com.nuoniu.sibanyun.service.erp.barcode.IErpBarcodeInOutService;
import com.nuoniu.sibanyun.service.erp.barcode.IErpNsInOutDetailService;
import com.nuoniu.sibanyun.service.erp.barcode.IErpNsInOutMainService;
import com.nuoniu.sibanyun.service.so.IVAreaCalculationDetailService;
import com.nuoniu.sibanyun.service.so.IVAreaCalculationMainService;
import com.nuoniu.sibanyun.userThread.UserInfo;
import com.nuoniu.sibanyun.userThread.UserThreadLocal;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * <p>
 * ERP非标 出入库主表 服务实现类
 * </p>
 *
 * @author 白强
 * @since 2021-11-30
 */
@Service
public class ErpNsInOutMainServiceImpl extends ServiceImpl<ErpNsInOutMainMapper, ErpNsInOutMain> implements IErpNsInOutMainService {

    @Autowired
    private IErpNsInOutDetailService erpNsInOutDetailService;
    @Autowired
    private IErpAccountService erpAccountService;
    @Autowired
    private ErpNumberSetMapper numberSetMapper;
    @Autowired
    private IErpNumberSetService numberSetService;
    @Autowired
    private ICrmGoodsService crmGoodsService;
    @Autowired
    private IErpBarcodeInOutService erpBarcodeInOutService;
    @Autowired
    private IVAreaCalculationMainService areaCalculationMainService;
    @Autowired
    private IVAreaCalculationDetailService areaCalculationDetailService;



    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void saveErpNsInOutMain(ErpNsInOutMain erpNsInOutMain) {
        Long mainId = erpNsInOutMain.getId();
        String dataSource = erpNsInOutMain.getDataSource();
        List<ErpNsInOutDetail> orderDetailList = erpNsInOutMain.getOrderDetailList();
        if(null == orderDetailList)throw new NuoNiuException("单据明细不能为空");
        UserInfo userInfo = UserThreadLocal.get();
        ErpNsInOutMain oldErpNsInOutMain = null;
        if(mainId != null) {
            //校验详情（详情不能有其他单据的明细ID）
            boolean isHaveErrorId = orderDetailList.stream().anyMatch(f -> null != f.getOrderId() && !mainId.toString().equals(f.getOrderId().toString()));
            if(isHaveErrorId)throw new NuoNiuException("单据明细错误：不能修改其他单据的明细记录");
            oldErpNsInOutMain = getById(mainId);
            Integer voucherState = oldErpNsInOutMain.getVoucherState();
            if(null != voucherState && voucherState > 0){
                throw new NuoNiuException("已审核,不能修改");
            }
        }else {

            String code = getCode(userInfo.getCompanyId(),dataSource);
            if(StringUtils.isBlank(code)) {
                throw new NuoNiuException("单据编码今日已上限");
            }
            //校验详情（详情不能有ID）
            boolean isHaveId = orderDetailList.stream().anyMatch(f -> null != f.getId());
            if(isHaveId)throw new NuoNiuException("单据明细错误：不能新增已经存在的明细记录");
            erpNsInOutMain.setCompanyId(userInfo.getCompanyId());
            erpNsInOutMain.setVoucherCode(code);
            erpNsInOutMain.setAccountId(erpAccountService.getCurrentAccountId());
            erpNsInOutMain.setCreateUserId(userInfo.getUserId());
            erpNsInOutMain.setCreateUserName(userInfo.getRealName());
        }

        // 校验 明细数量
        boolean isOk = erpNsInOutMain.getOrderDetailList().stream().anyMatch(f -> null == f.getQuantity() || !(f.getQuantity().compareTo(BigDecimal.ZERO) > 0));
        if(isOk)throw new NuoNiuException("明细数量必须大于0");
        boolean isDetailBarcodesNull = erpNsInOutMain.getOrderDetailList().stream().anyMatch(f -> StringUtils.isBlank(f.getBarcodes()));
        if(isDetailBarcodesNull)throw new NuoNiuException("单据明细缺失条码");
        //计算 明细物料 总数
        BigDecimal totalQuantity =  erpNsInOutMain.getOrderDetailList().stream().map(ErpNsInOutDetail::getQuantity).reduce(BigDecimal.ZERO,BigDecimal::add);
        erpNsInOutMain.setTotalQuantity(totalQuantity.abs());
        Boolean result = this.saveOrUpdate(erpNsInOutMain);
        if(result) {
            List<Long> detailIds = new ArrayList<>();
            orderDetailList.forEach(p -> {
                p.setOrderId(erpNsInOutMain.getId().intValue());
                p.setCompanyId(userInfo.getCompanyId());
                p.setAccountId(erpNsInOutMain.getAccountId());
                if(p.getId() != null) {
                    detailIds.add(p.getId());
                }
            });
            if (null != mainId){
                //删除明细
                QueryWrapper wrapper = new QueryWrapper();
                wrapper.eq("order_id", mainId);
                if(detailIds != null && detailIds.size() > 0) {
                    wrapper.notIn("id", detailIds);
                }
                erpNsInOutDetailService.remove(wrapper);
            }
            //保存单据明细表
            erpNsInOutDetailService.saveOrUpdateBatch(orderDetailList);
        }

    }

    @Override
    public String getCode(Integer companyId,String dataSource) {
        UserInfo userInfo = UserThreadLocal.get();
        Integer currentAccountId = erpAccountService.getCurrentAccountId();
        ErpNumberSet numberSet = numberSetMapper.getByCode(dataSource, userInfo.getCompanyId(), currentAccountId);
        String dateStr = numberSet.getMedian() == 1 ? "%Y-%m-%d" : "%Y-%m";
        String code = baseMapper.getCode(userInfo.getCompanyId(), dateStr,dataSource);
        return numberSetService.getCode(numberSet, code);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void examine(Long id, Integer status) {
        if(0 != status && 1 != status)throw new NuoNiuException("参数错误");
        UserInfo userInfo = UserThreadLocal.get();
        ErpNsInOutMain erpNsInOutMain = getById(id);
        if(erpNsInOutMain == null) {
            throw new NuoNiuException("单据不存在");
        }
        Integer voucherState = erpNsInOutMain.getVoucherState();
        if(0 == status && 1 != voucherState)throw new NuoNiuException("弃审失败,单据不是已审核状态");
        if(1 == status && 0 != voucherState)throw new NuoNiuException("审核失败,单据不是未审核状态");

        erpNsInOutMain.setVoucherState(status);
        erpNsInOutMain.setReviewerDate(LocalDate.now());
        erpNsInOutMain.setReviewerUserId(userInfo.getUserId());
        erpNsInOutMain.setReviewerUserName(userInfo.getRealName());
        updateById(erpNsInOutMain);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void deleteById(Long id) {
        UserInfo userInfo = UserThreadLocal.get();
        ErpNsInOutMain erpNsInOutMain = getById(id);
        if(erpNsInOutMain == null) {
            throw new NuoNiuException("单据已删除");
        }
        Integer voucherState = erpNsInOutMain.getVoucherState();
        if(0 != voucherState)throw new NuoNiuException("删除失败，已经审核，请先弃审");
        /**************  修改权限 *******************/
        if(!crmGoodsService.isHaveOperationRight(erpNsInOutMain.getCreateUserId().longValue())){
            throw new NuoNiuException("你没有权限操作该记录");
        }
        removeById(id);
        erpNsInOutDetailService.removeByOrderId(id);
    }

    /**
     * 扫描出库
     * @param mainId
     * @param barcode
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public ErpNsInOutMain saveFromBarcode(Long mainId, String barcode) {
        ErpNsInOutMain erpNsInOutMain;
        LocalDateTime now = LocalDateTime.now();
        Integer currentAccountId = erpAccountService.getCurrentAccountId();
        UserInfo userInfo = UserThreadLocal.get();
        /** 校验条码出入库状态 并获取 面积计算表明细 */
        VAreaCalculationMain areaCalculationMain = areaCalculationMainService.analysisByBarCode(barcode, 2);
        if( null == areaCalculationMain)throw new NuoNiuException("出库失败，查询不到条码信息");
        Integer projectId = areaCalculationMain.getProjectId();
        String batch = areaCalculationMain.getBatch();
        /** 一、如果 mainId 为空*/
        if ( null == mainId ){
            erpNsInOutMain = new ErpNsInOutMain();
            erpNsInOutMain.setCompanyId(userInfo.getCompanyId());
            erpNsInOutMain.setAccountId(currentAccountId);
            erpNsInOutMain.setCreateUserId(userInfo.getUserId());
            erpNsInOutMain.setDataSource("NSSaleDispatchVoucher");
            erpNsInOutMain.setCreateUserName(userInfo.getRealName());
            erpNsInOutMain.setCreateDate(now);
            erpNsInOutMain.setChargeUserId(userInfo.getUserId());
            erpNsInOutMain.setChargeUserName(userInfo.getRealName());
            erpNsInOutMain.setVoucherCode(areaCalculationMainService.getCode());
            erpNsInOutMain.setVoucherDate(now.toLocalDate());
            erpNsInOutMain.setVoucherState(0);
            erpNsInOutMain.setBatch(batch);
            erpNsInOutMain.setProjectId(projectId);
            erpNsInOutMain.setProjectCode(areaCalculationMain.getProjectCode());
            erpNsInOutMain.setProjectName(areaCalculationMain.getProjectName());

            List<ErpNsInOutDetail> erpNsInOutDetails = new ArrayList<>();
            ErpNsInOutDetail erpNsInOutDetail = new ErpNsInOutDetail();
            erpNsInOutDetails.add(erpNsInOutDetail);
            erpNsInOutMain.setOrderDetailList(erpNsInOutDetails);

            List<VAreaCalculationDetail> orderDetailList = areaCalculationMain.getOrderDetailList();
            VAreaCalculationDetail areaCalculationDetail = orderDetailList.get(0);
            BeanUtils.copyProperties(areaCalculationDetail,erpNsInOutDetail);
            erpNsInOutDetail.setId(null);
            erpNsInOutDetail.setOrderId(null);
            erpNsInOutDetail.setBarcodes(barcode);
            erpNsInOutDetail.setQuantity(BigDecimal.ONE);
            erpNsInOutDetail.setSourceDetailId(areaCalculationDetail.getId().intValue());
            erpNsInOutDetail.setSourceVoucherId(areaCalculationDetail.getOrderId());
            erpNsInOutDetail.setSourceVoucherCode(areaCalculationMain.getVoucherCode());
            erpNsInOutDetail.setSourceVoucherDate(areaCalculationMain.getVoucherDate());
            erpNsInOutDetail.setSourceVoucherType("AreaCalculation");
            /**  保存 发货单 */
            saveErpNsInOutMain(erpNsInOutMain);

            /** 更新 并校验 条码出入库 */
            erpBarcodeInOutService.bathUpdateOutRecord(erpNsInOutDetails);

        }else {
            erpNsInOutMain = getById(mainId);
            if (null == erpNsInOutMain || !erpNsInOutMain.getCompanyId().equals(userInfo.getCompanyId()))throw new NuoNiuException("查询不到发货单主表信息");
            ErpNsInOutMain newErpNsInOutMain = new ErpNsInOutMain();
            newErpNsInOutMain.setId(erpNsInOutMain.getId());
            String oldBatch = erpNsInOutMain.getBatch();
            List<String> batchList = Arrays.asList(oldBatch.split(","));
            /** 校验 项目名称 是否一致 */
            if(!projectId.equals(erpNsInOutMain.getProjectId()))throw new NuoNiuException("条码查询到了项目信息不一致");
            if(!batchList.contains(batch)){
                newErpNsInOutMain.setBatch(oldBatch + "," +batch);
                /**  更新 发货单 */
                updateById(newErpNsInOutMain);
            }



            List<VAreaCalculationDetail> orderDetailList = areaCalculationMain.getOrderDetailList();
            VAreaCalculationDetail areaCalculationDetail = orderDetailList.get(0);
            Long detailId = areaCalculationDetail.getId();

            /**   校验 明细  并保存更新  */
            ErpNsInOutDetail oldErpNsInOutDetail = erpNsInOutDetailService.getByMainIdAndSourceDetailId(mainId, detailId.intValue());
            if ( null != oldErpNsInOutDetail){
                ErpNsInOutDetail newErpNsInOutDetail = new ErpNsInOutDetail();
                newErpNsInOutDetail.setId(oldErpNsInOutDetail.getId());
                newErpNsInOutDetail.setQuantity(oldErpNsInOutDetail.getQuantity().add(BigDecimal.ONE));
                newErpNsInOutDetail.setBarcodes(oldErpNsInOutDetail.getBarcodes()+","+barcode);
                erpNsInOutDetailService.updateById(newErpNsInOutDetail);
                /** 明细 返回给前端 使用 */
                List<ErpNsInOutDetail> erpNsInOutDetails = new ArrayList<>();
                oldErpNsInOutDetail.setQuantity(newErpNsInOutDetail.getQuantity());
                oldErpNsInOutDetail.setBarcodes(newErpNsInOutDetail.getBarcodes());
                erpNsInOutDetails.add(oldErpNsInOutDetail);
                erpNsInOutMain.setOrderDetailList(erpNsInOutDetails);
            }else{
                ErpNsInOutDetail erpNsInOutDetail = new ErpNsInOutDetail();
                BeanUtils.copyProperties(areaCalculationDetail,erpNsInOutDetail);
                erpNsInOutDetail.setId(null);
                erpNsInOutDetail.setOrderId(mainId.intValue());
                erpNsInOutDetail.setBarcodes(barcode);
                erpNsInOutDetail.setQuantity(BigDecimal.ONE);
                erpNsInOutDetail.setSourceDetailId(detailId.intValue());
                erpNsInOutDetail.setSourceVoucherId(areaCalculationDetail.getOrderId());
                erpNsInOutDetail.setSourceVoucherCode(areaCalculationMain.getVoucherCode());
                erpNsInOutDetail.setSourceVoucherDate(areaCalculationMain.getVoucherDate());
                erpNsInOutDetail.setSourceVoucherType("AreaCalculation");
                /** 保存 */
                erpNsInOutDetailService.save(erpNsInOutDetail);
                List<ErpNsInOutDetail> erpNsInOutDetails = new ArrayList<>();
                erpNsInOutDetails.add(erpNsInOutDetail);
                erpNsInOutMain.setOrderDetailList(erpNsInOutDetails);
            }
            List<String> barcodes = new ArrayList<>();
            barcodes.add(barcode);
            /** 更新 并校验 条码出入库 */
            erpBarcodeInOutService.bathUpdateOutRecordFromBarcodes(barcodes);
        }

        return erpNsInOutMain;
    }
}
